package com.namuan.jp_stock.util;

import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Stack;


import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.widget.ImageView.ScaleType;

public class CustomImageManager {

	// Just using a hashmap for the cache. SoftReferences would
	// be better, to avoid potential OutOfMemory exceptions
	private HashMap<String, Bitmap> imageMap = new HashMap<String, Bitmap>();
	private int DefaultImage;
	private File cacheDir;
	private ImageQueue imageQueue = new ImageQueue();
	private PointImageQueue pointImageQueue = new PointImageQueue();
	private Thread imageLoaderThread = new Thread(new ImageQueueManager());

	public CustomImageManager(Context context, int DefaultImage) {
		// Make background thread low priority, to avoid affecting UI
		// performance
		imageLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);
		this.DefaultImage = DefaultImage;
		// Find the dir to save cached images
		String sdState = android.os.Environment.getExternalStorageState();
		if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) {
			File sdDir = android.os.Environment.getExternalStorageDirectory();
			cacheDir = new File(sdDir, "data/codehenge");
		} else
			cacheDir = context.getCacheDir();

		if (!cacheDir.exists())
			cacheDir.mkdirs();
	}

	// 추가 - wine Image resizing 함수
	public void displayPointImage(String url, Activity activity,
			PointImageView pointImageView) {
		Log.d("urls", url);
		if (url != null && !url.equals("null")) {
			Log.d("okurls", url);
			if (imageMap.containsKey(url)) {
				Log.d("inokurls", url);
				pointImageView.setImageBitmap(null);
				pointImageView.setScaleType(ScaleType.CENTER_CROP);
				pointImageView.setImageBitmap(imageMap.get(url));
			} else {
				queuePointImage(url, activity, pointImageView);

			}
		} else {
			pointImageView.setImageBitmap(null);
			pointImageView.setScaleType(ScaleType.CENTER_CROP);
			pointImageView.setImageResource(DefaultImage);
		}
	}

	public void displayImage(String url, Activity activity,
			ProfileImageView ProfileImageView) {
		Log.d("urls", url);
		if (url != null && !url.equals("null")) {
			Log.d("okurls", url);
			if (imageMap.containsKey(url)) {
				Log.d("inokurls", url);
				ProfileImageView.setImageBitmap(null);
				ProfileImageView.setScaleType(ScaleType.CENTER_CROP);
				ProfileImageView.setImageBitmap(imageMap.get(url));
			} else {
				queueImage(url, activity, ProfileImageView);
			}
		} else {
			ProfileImageView.setImageBitmap(null);
			ProfileImageView.setScaleType(ScaleType.CENTER_CROP);
			ProfileImageView.setImageResource(DefaultImage);
		}
	}

	private void queueImage(String url, Activity activity,
			ProfileImageView ProfileImageView) {
		// This ProfileImageView might have been used for other images, so we
		// clear
		// the queue of old tasks before starting.
		imageQueue.Clean(ProfileImageView);
		ImageRef p = new ImageRef(url, ProfileImageView);

		synchronized (imageQueue.imageRefs) {
			imageQueue.imageRefs.push(p);
			imageQueue.imageRefs.notifyAll();
		}

		// Start thread if it's not started yet
		if (imageLoaderThread.getState() == Thread.State.NEW)
			imageLoaderThread.start();
	}

	private void queuePointImage(String url, Activity activity,
			PointImageView pointImageView) {
		// This ProfileImageView might have been used for other images, so we
		// clear
		// the queue of old tasks before starting.
		pointImageQueue.Clean(pointImageView);
		PointImageRef p = new PointImageRef(url, pointImageView);

		synchronized (pointImageQueue.pointImageRefs) {
			pointImageQueue.pointImageRefs.push(p);
			pointImageQueue.pointImageRefs.notifyAll();
		}

		// Start thread if it's not started yet
		if (imageLoaderThread.getState() == Thread.State.NEW)
			imageLoaderThread.start();
	}

	private Bitmap getBitmap(String url) {

		String filename = String.valueOf(url.hashCode());
		Log.d("filename", filename);
		File f = new File(cacheDir, filename);

		// Is the bitmap in our cache?
		BitmapFactory.Options opts1 = new BitmapFactory.Options();
		opts1.inJustDecodeBounds = true;
		Bitmap bitmap = BitmapFactory.decodeFile(filename, opts1);
		opts1 =Util.getProfileBitmapSize(opts1);
		bitmap = BitmapFactory.decodeFile(filename, opts1);
		if (bitmap != null)
			return bitmap;

		// Nope, have to download it
		try {
			BitmapFactory.Options opts = new BitmapFactory.Options();
			opts.inJustDecodeBounds = true;
			bitmap = BitmapFactory.decodeStream(new URL(url).openConnection().getInputStream(), null, opts);
			opts =Util.getProfileBitmapSize(opts);
			bitmap = BitmapFactory.decodeStream(new URL(url).openConnection().getInputStream(), null, opts);
			//bitmap = BitmapFactory.decodeResource(mRes, mRes.getIdentifier(fileName, null, null), opts).
			// save bitmap to cache for later
			writeFile(bitmap, f);

			return bitmap;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}
	}

	private void writeFile(Bitmap bmp, File f) {
		Log.d("writeFile", "");
		FileOutputStream out = null;

		try {
			out = new FileOutputStream(f);
			bmp.compress(Bitmap.CompressFormat.PNG, 40, out);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null)
					out.close();
			} catch (Exception ex) {
			}
		}
	}

	/** Classes **/

	private class ImageRef {
		public String url;
		public ProfileImageView ProfileImageView;

		public ImageRef(String u, ProfileImageView i) {
			url = u;
			ProfileImageView = i;
		}
	}

	// stores list of images to download
	private class ImageQueue {
		private Stack<ImageRef> imageRefs = new Stack<ImageRef>();

		// removes all instances of this ProfileImageView
		public void Clean(ProfileImageView view) {

			for (int i = 0; i < imageRefs.size();) {
				if (imageRefs.get(i).ProfileImageView == view)
					imageRefs.remove(i);
				else
					++i;
			}
		}
	}

	// stores list of images to download
	private class PointImageQueue {
		private Stack<PointImageRef> pointImageRefs = new Stack<PointImageRef>();

		// removes all instances of this ProfileImageView
		public void Clean(PointImageView view) {

			for (int i = 0; i < pointImageRefs.size();) {
				if (pointImageRefs.get(i).pointImageView == view)
					pointImageRefs.remove(i);
				else
					++i;
			}
		}
	}
	private class PointImageRef {
		public String url;
		public PointImageView pointImageView;

		public PointImageRef(String u, PointImageView i) {
			url = u;
			pointImageView = i;
		}
	}

	private class PointImageQueueManager implements Runnable {
		@Override
		public void run() {
			try {
				while (true) {
					// Thread waits until there are images in the
					// queue to be retrieved
					if (pointImageQueue.pointImageRefs.size() == 0) {
						synchronized (pointImageQueue.pointImageRefs) {
							pointImageQueue.pointImageRefs.wait();
						}
					}

					// When we have images to be loaded
					if (pointImageQueue.pointImageRefs.size() != 0) {
						PointImageRef pointImageToLoad;

						synchronized (pointImageQueue.pointImageRefs) {
							pointImageToLoad = pointImageQueue.pointImageRefs.pop();
						}

						Bitmap bmp = getBitmap(pointImageToLoad.url);
						imageMap.put(pointImageToLoad.url, bmp);
						Object tag = pointImageToLoad.pointImageView.getTag();

						// Make sure we have the right view - thread safety
						// defender
						if (tag != null
								&& ((String) tag).equals(pointImageToLoad.url)) {
							BitmapDisplayer bmpDisplayer = new BitmapDisplayer(
									bmp, pointImageToLoad.pointImageView);

							Activity a = (Activity) pointImageToLoad.pointImageView
									.getContext();

							a.runOnUiThread(bmpDisplayer);
						}
					}

					if (Thread.interrupted())
						break;
				}
			} catch (InterruptedException e) {
			}
		}
	}

	private class ImageQueueManager implements Runnable {
		@Override
		public void run() {
			try {
				while (true) {
					// Thread waits until there are images in the
					// queue to be retrieved
					if (imageQueue.imageRefs.size() == 0) {
						synchronized (imageQueue.imageRefs) {
							imageQueue.imageRefs.wait();
						}
					}

					// When we have images to be loaded
					if (imageQueue.imageRefs.size() != 0) {
						ImageRef imageToLoad;

						synchronized (imageQueue.imageRefs) {
							imageToLoad = imageQueue.imageRefs.pop();
						}

						Bitmap bmp = getBitmap(imageToLoad.url);
						imageMap.put(imageToLoad.url, bmp);
						Object tag = imageToLoad.ProfileImageView.getTag();

						// Make sure we have the right view - thread safety
						// defender
						if (tag != null
								&& ((String) tag).equals(imageToLoad.url)) {
							BitmapDisplayer bmpDisplayer = new BitmapDisplayer(
									bmp, imageToLoad.ProfileImageView);

							Activity a = (Activity) imageToLoad.ProfileImageView
									.getContext();

							a.runOnUiThread(bmpDisplayer);
						}
					}

					if (Thread.interrupted())
						break;
				}
			} catch (InterruptedException e) {
			}
		}
	}

	// Used to display bitmap in the UI thread
	private class BitmapDisplayer implements Runnable {
		Bitmap bitmap;
		ProfileImageView ProfileImageView = null;
		PointImageView pointImageView = null;

		public BitmapDisplayer(Bitmap b, ProfileImageView i) {
			bitmap = b;
			ProfileImageView = i;
		}

		public BitmapDisplayer(Bitmap b, PointImageView i) {
			bitmap = b;
			pointImageView = i;
		}

		public void run() {
			if (bitmap != null) {
				if (pointImageView == null) {
					ProfileImageView.setScaleType(ScaleType.CENTER_CROP);
					ProfileImageView.setImageBitmap(bitmap);
				} else {
					pointImageView.setScaleType(ScaleType.CENTER_CROP);
					pointImageView.setImageBitmap(bitmap);
				}

			}

			else {
				if (pointImageView == null) {
					ProfileImageView.setScaleType(ScaleType.CENTER_CROP);
					ProfileImageView.setImageResource(DefaultImage);
				} else {
					pointImageView.setScaleType(ScaleType.CENTER_CROP);
					pointImageView.setImageResource(DefaultImage);
				}
			}
		}
	}
}